#pragma once
#ifndef PROTO_DISPATCH_H_
#define PROTO_DISPATCH_H_

#include <map>
#include <string>

#include "google/protobuf/message.h"
#include "common.h"


using namespace google::protobuf;
using namespace std;


class callback
{
public:
	virtual int OnMessage(Message * msg, void *) = 0;

	virtual ~callback() {}
};

template<class T>
class CallBack_T : public callback
{
public:
	typedef int(*protocallback)(T *, void *);
	CallBack_T(protocallback pt) :_back(pt) {}

	//提供一个任意类型的参数
	//要想有扩展性，就提供一个void *类型的参数
	virtual int OnMessage( Message * msg, void * param)
	{
		//强制转换，将基类的msg类型转换成T类型
		T * promsg = dynamic_cast<T *>(msg);

		return _back(promsg, param);
	}

private:
	protocallback _back;
};

class Distpater
{
public:
	int Dispath( Message * msg, void * param)
	{
		//根据消息对象指针，获取对应的Descriptor
		const Descriptor * des = msg->GetDescriptor();

		CallMAP::const_iterator it = msg_callback.find(des);

		if (it != msg_callback.end())
		{
			return msg_callback[des]->OnMessage(msg, param);
		}
		else
		{
			//do nothing
			return proto_no_callback;
		}
	}

	template <typename T>
	void Register(const typename CallBack_T<T>::protocallback & protocall)
	{
		CallBack_T<T> * call = new  CallBack_T<T>(protocall);

		//设置从Descriptor到回调类对象指针的映射
		msg_callback[T::descriptor()] = call;
	}

private:
	typedef map<const Descriptor *, callback *> CallMAP;
	CallMAP msg_callback;   //消息与回调的映射关系
};

#endif  //PROTO_DISPATCH_H_
